HTBasic for Windows 9.0 Numeric Compiler
HTBasic for Windows 9.3 Numeric Compiler Contents

Chapter 1	Why a Numeric Compiler?

Chapter 2	Running the Compiler

Chapter 3	Compiler Limitations

Chapter 4	Producing Optimal CSUBs

Chapter 5 	Errors

Chapter 6 	Definitions

Chapter 7 	Statement Lists

Other Manuals

Basic Plus
Installing and Using
Reference Manual
User's Guide

Distributed with release 9.3

Copyright ® 1988-2005 by TransEra Corp.


Why a Numeric Compiler?

The HTBasic for Windows 9.3 Numeric Compiler is designed so the casual HTBasic user can produce fast, numerically intensive subprograms. The user writes one or more SUBs in HTBasic that contain the numerically intensive code. The SUB or SUBs are then compiled, creating CSUBs that execute many times faster than the original HTBasic code. No additional programming skill is necessary.

Speed of execution of numerically intensive subprograms is the main goal of the Numeric Compiler. It is neither intended nor expected that every SUB in a program be compiled.

The HTBasic for Windows 9.3 Numeric Compiler does not produce CSUBs from C or 386/486 assembly language. The CSUB Toolkit allows creation of CSUBs from these languages. The CSUB Toolkit is aimed toward users writing system level code. Using the CSUB Toolkit requires more extensive programming skills and a larger investment of time.

Because the Numeric Compiler is designed for numeric algorithms, there are limitations to what it can do. It is recommended that the user completely read this manual before trying to use the Numeric Compiler, as this will save a considerable amount of time and trouble.

After reading this section of the manual, it may initially appear that a considerable amount of work is involved in changing a program to make it suitable for compilation.  This is not the case. If care is taken in selecting specific SUBs for compilation, rather than expecting to compile an entire program, very little effort is usually required, and the rewards are tremendous. Simple REAL operators are 20 to 35 times faster. More complex operators, like SIN, are 6 to 8 times faster. In testing the compiler we found some SUBs enjoyed a speed increase of as much as 56 times the original speed!


What does it do?

The HTBasic for Windows 9.3 Numeric Compiler takes HTBasic subprograms and produces equivalent Pentium machine code subprograms. The HTBasic for Windows 9.3 Numeric Compiler is a 32-bit compiler for Pentium processors. The Numeric Compiler produces code to run in 32-bit protected mode, which is the fastest and most powerful mode of these advanced processors.

The Numeric Compiler uses common optimization methods to enhance program execution speed. It produces in-line math instructions for all math operators, making the resulting math routines faster than those produced by other computer languages. When possible, operations on constants are made at compile-time rather than run-time.

The CSUBs produced are compatible with other HTBasic SUBs. CSUBs can be loaded and executed alongside HTBasic subprograms. LOAD, STORE, LOADSUB, DELSUB, CALL, on event CALL and CAT commands handle CSUBs in addition to interpreted SUBs.


Licensing

The subprograms produced by the compiler are not the property of TransEra Corporation. The runtime system and environment manager are the property of TransEra Corporation and are supplied under license. The TransEra License Agreement is printed in the CD booklet. If you wish to execute the programs produced by the compiler on more computers than allowed by the license, additional HTBasic runtime licenses may be purchased.


Requirements

The Numeric Compiler is now included in HTBasic Development version 9.3. The Development version of HTBasic is needed to edit and prepare programs for compilation. You must have either the HTBasic Development or the Runtime version to run the programs after compiling.  CSUBs compiled with the HTBasic for Windows 9.3 Numeric Compiler can be run with HTBasic Development or Runtime version 9.3 or newer.


Running the Compiler

Before running the compiler, you should make sure the subprogram you wish to compile is prepared properly. The subprogram must be prerun and stored in a PROG file using HTBasic. To prerun all the subprograms in a PROG file:

⋅	Run HTBasic

⋅	Load the program into memory

⋅	Press STEP (Alt-F1)

⋅	Use STORE or RE-STORE (not SAVE/RE-SAVE) to create the PROG file.

If the PROG file has no Main program, you must add one before the file can be prerun. In many cases, inserting an END statement before the first SUB or DEF statement will suffice. However, if any of the subprograms contain COM statements without array subscript bounds or string lengths, then COM statements, which appropriately declare them, must be added to the Main program.


Starting the Compiler

The compiler is invoked from within HTBasic for Windows.  From the Tools Menu, select Numeric Compiler.  The HTBasic Numeric Compiler window will appear:


Source File

Enter the name of the PROG file that contains the subprogram to be compiled, including the file path, or click the Browse button to invoke a File dialog.


Output File

Enter the name of the PROG file that will contain the newly compiled CSUB. If a file already exists with the name you specify, the old file with that name will be erased and replaced with the compiler output. Do not use the same name as the source file without specifying a different extension (.csb). A default filename is listed in the Output file field.  The default filename is only a suggestion and is formed by replacing the extension of the source filename with "CSB". If you wish to use the default filename, you can press Run without typing the filename. If you wish to use a different filename, just type it in. If you don't enter an extension, the "CSB" extension will be used. The following examples assume that "BENCH.PRG" was given as the source filename.

If you type	This name is used by the compiler
OUTPUT.PRG	OUTPUT.PRG
BENCH.CSB	BENCH.CSB
BENCH	BENCH.CSB
(nothing)	BENCH.CSB
BENCH.	BENCH


SUB Name

In the SUB Name field, type the name of the SUB to be compiled. Only SUBs may be compiled. The MAIN program and user defined functions (DEF FN) cannot be compiled.

It is possible to compile all the SUBs in a PROG file. This is done by checking the Compile All Subprograms Checkbox.  Compiling all the SUBs in a PROG file is useful when you have constructed a library of SUBs suitable for compilation. Most SUBs contain string or user interface statements that are not compatible with the compiler, as explained in the Compiler Limitations section.  Thus, it is incorrect to assume that this feature can be used to completely compile arbitrary programs.

It is also possible to compile some combination of the SUBs in a PROG file.  This can be done by typing the SUB names separated by a semicolon.  For example, if there are three Subprograms of a PROG file to be compiled, named Sub1, Sub2 and Sub3, the following could be typed into the text box to compile all three SUBs at once.

 Multiple SUBs in a PROG file can also be compiled by clicking the Select button to the right of the Sub Name text box.  The Numeric Compiler – Available Subs window will appear:

The available SUBs that can be compiled appear on the right, and they can be transferred to and from the Sub List on the left using the Add Sub, Remove Sub, Clear All, and Select All buttons.

When the Add Sub button is clicked, the selected SUB or SUBs in the Available Subs box are moved to the Sub List box.  When the Remove Sub button is clicked, the selected SUB or SUBs in the Sub List box are moved to the Available Subs box.  When Clear All is clicked, any SUBs in the Sub List box are moved to the Available Subs box.  When Select All is clicked, all SUBs in the Available Subs box are selected.  When OK is clicked, the Numeric Compiler-Available Subs window is closed, and the selected SUBs appear in the Sub Name text box of the HTBasic Numeric Compiler window.


Compiler Switches

Optionally, compiler switches can be specified to control certain aspects of the Numeric Compiler. These switches are listed below the SUB Name field.  Each switch can be turned on by checking the corresponding checkbox, or turned off by un-checking the checkbox.

 The switches are explained in the following paragraphs.


Produce End-Of-Line in the code:

Normally, there is no way to interrupt a CSUB. The keyboard and all ON event statements are ignored while the CSUB executes. If this switch is on, then between each program line a call is made to the environment manager to see if the RESET key has been pressed. If the RESET key has been pressed, the program will stop. It is recommended that this switch be turned off most of the time, since the call to the environment manager slows down the CSUB significantly. The default value for this switch is off.

The following example illustrates a technique that minimizes slow execution caused by this switch while still allowing the CSUB to be terminated with the RESET key.  The switch can be abbreviated as "EOL" and turned on and off within the subprogram.    As an example, look at the following program:

10	END

20	SUB Compute(X,Y,Z)

30	INTEGER I,J,J1

 .

70	FOR I=1 TO 50

90	  	 !$EOL ON

100	 !$EOL OFF

110	 FOR J=1 TO 2000

  .

130	 NEXT J

140	  	NEXT I

150	Z=J1*X+K1*Y

160	SUBEND

If the inner loop (J) takes about one second to execute, the entire routine will take about 90 seconds to execute. Between lines 90 and 100 a check is made for the RESET key. Only 90 checks will be made during the entire program, yet the RESET key will be seen within a second. In contrast, if EOL were on for the entire routine and more than ten lines existed inside the inner loop, over 1.8 million checks would be made. Thus, there would be a significant increase in execution time with little improvement in RESET responsiveness.


Produce inline code for the power "^" operator

This switch instructs the compiler to use in-line code to raise a number to a power (i.e., using the "^" operator). Normally, when a calculation involves raising a number to a power, the compiler calls a library routine. This operation is relatively slow, so the compiler will try to speed up the operation. If the exponent is a small integral constant, the compiler makes the calculation using repeated multiplies. If the base is a positive constant, the compiler generates in-line code.

However, if constants are not used, the compiler doesn't know at compile-time if in-line code can be safely generated. The in-line code works only if the base is positive. In cases where you know that the base will always be positive, use this switch to tell the compiler to generate in-line code.

If the "^" operator is used several times in a program, but only some of those instances have a base that will always be positive, there is a different technique for using this switch.  The switch can be abbreviated as "POW" and turned on and off within the subprogram.  As an example, look at the following program.

10  END

20  SUB P

30	 FOR X=2 TO 3

40	FOR Y=0 TO 5

41	  !$POW ON

50	  Z=X^Y

51	  !$POW OFF

60	  PRINT X;"^";Y;"=";Z

70	NEXT Y

80	 NEXT X

90  SUBEND

In line 50, X will always be positive. This switch can safely be included in line 41 and the calculation of X^Y will be much faster.  The switch is then turned off in line 51.


Disallow REDIM and produce faster array code

This switch allows the compiler to create faster code for handling of local arrays. The default value for this switch is on. If you must REDIM a local array, the Disallow REDIM and produce faster array code switch must be off.  The switch must be turned off either on the command line or before any executable statements in a subprogram.

If Disallow REDIM and produce faster array code is on, the compiler's knowledge of the BASE and SIZE of a local array allows it to generate highly optimized code for accessing the array. If Disallow REDIM and produce faster array code is off, the compiler has no knowledge of the BASE and SIZE of the array. All calculations that could have been done at compile time must be done at run-time, which slows down execution speed.

The switch can be abbreviated as "SA" and turned on and off within the subprogram.  The following example shows how to turn this switch off before any executable statements in a subprogram.

10  SUB Op1

20	!$SA OFF

30	INTEGER I(5:8,0:1)

.

70	REDIM I(0:1,0:3)

.

90  SUBEND


Produce Array subscript range checking code

This switch allows the compiler to create code that range checks all array subscripts. The default value for this switch is off. This switch can be used both in the Numeric Compiler and anywhere in a subprogram to enable and disable array subscript checking.

If array subscript checking is on, the compiler generates code to range check each array subscript value against the legal values specified in the array's DIM statement. Subscript checking generates large amounts of code and slows down array element access speed.

This switch should be used while debugging new subprograms or looking for execution problems where invalid array element access is suspected. After the problem(s) have been identified and corrected, make sure the subprogram is recompiled with this option off to regain faster execution speed.

The following example shows how to use the array subscript checking option, abbreviated as "SC", within a subprogram to control the generation of subscript checking code.

10	SUB Op1

.

30	  A=I(5,8,0,1) !No checking

.

50	  !$SC ON

.

70	  A=J(N,L) !Checking

.

80	  !$SC OFF

90	SUBEND


Print Warning Messages

Warning messages are generated for conditions that may prevent the CSUB from executing correctly or for non-optimal coding in your Subprogram. Warning messages do not prevent the Subprogram from being compiled and are not normally printed. Note, however, that the warning message generated by the PAUSE statement is always printed.

If you are having execution problems with your SUB, it is useful to turn the Print Warning Messages switch on. This will alert you to the program lines that could be causing problems.

The default value for this switch is off. The following example shows how to turn warnings on in the program code, abbreviated as "WA."

10  END

20  SUB Sum(A(*),S)

21	!$WA ON

30	S=0

40	FOR I=1 TO 25

50	S=S+A(I)

60	NEXT I

70  SUBEND

The following warnings are printed for the previous example:

 A quick look over the program shows that the variable "I" always has an integral value. If it were declared as an INTEGER, the Subprogram would execute much faster. This is true for both compiled and uncompiled Subprograms.

Please note that there are situations where changing a variable to INTEGER can actually make the SUB execute slower. If the variable is used in many expressions requiring a REAL value, then the extra time required to convert the value from INTEGER to REAL in each expression could make the program slower than when the variable was REAL. When in doubt, time the program each way to determine the faster method.


Allocate data space for temporary results

The compiler allocates data space for any temporary results that must be saved to memory. In rare instances, the necessary amount of memory cannot be allocated. Preallocating more memory can prevent this situation. The default value for this switch is eight.

If error 216 occurs during compilation, the default number of temporary memory, eight, was not enough. Use the Allocated data space for temporary results switch to specify a larger value. Depending on how much memory is needed, this may need to be increased a few times until the amount is large enough that error 216 no longer occurs.


Produce a listing file of compiler errors

This switch produces a listing file, which contains a list of any compiler errors produced during compilation. Warning messages can also be listed by turning the Print Warning Messages switch on. If several errors occur, it is useful to produce a listing file and then print the listing file to refer to while correcting the program errors. By default, no listing file is created. To produce a listing file, specify the filename in the Listing File text box, or use the Browse button to select a directory or file.

The listing file contains the same information that appears in the Output section of the HTBasic Numeric Compiler window.

If you wish the listing to go to a file, enter the filename. The extension "LST" will be assumed if you do not specify one. For example:

If you type	This name is used by the compiler
BENCH.LST	BENCH.LST
BENCH	BENCH.LST
BENCH.	BENCH
BENCH.TXT	BENCH.TXT
This compiler switch cannot be embedded into a subprogram.


Compilation

Click the Run button in the HTBasic Numeric Compiler window to start the compiler. The compiler checks each subprogram in the source file. If the subprogram is not named for compilation, it is copied to the output file unchanged. If the subprogram is to be compiled, the compiler begins to compile it. If no compile errors are found, the new compiled CSUB is placed in the output file. In place of the subprogram declaration and code will be a CSUB statement. In some instances, the compiler uses several line numbers for a CSUB. The additional lines do not contain readable HTBasic statements. The line numbers are reserved with a single asterisk. No lines of a CSUB can be changed with the HTBasic editor.

If warnings occur, but there are no errors, the CSUB is produced and placed in the output file. Warnings can be ignored and are not normally listed. Warnings usually indicate non-optimum program constructs. If errors occur, the subprogram is not compiled and the original HTBasic Subprogram is copied to the output file unchanged. The errors are listed on the screen. The errors must be corrected before the SUB can be compiled. See the section on Compiler Switches for a method of listing the error messages to a file.

During compilation, a progress report similar to the one below is printed in the Output section of the HTBasic Numeric Compiler window.

 After all subprograms have been processed, the compiler stops. The user can then compile subprograms from another source file, or exit the numeric compiler.  The Clear Output button clears all output from the Output section of the HTBasic Numeric Compiler window.  The Exit button closes the HTBasic Numeric Compiler window.


Compiler Limitations

The Numeric Compiler is designed to produce fast, calculation intensive subprograms. The following paragraphs explain limitations of the compiler. Some of the limitations result from this design goal; others are inherent to the compiled environment.


Statement Types

The compiler divides all programmable statements into three types:

Type 1 - Completely compiled

Type 2 - Partially compiled

Type 3 - Not compilable

In a similar manner, operators and operands are divided into two types:

Type 1 - Completely compiled if used in a Type 1 Statement

Type 2 - Completely interpreted

Whenever possible, Type 1 Statements and Type 1 Operators/Operands should be used. Type 2 operators/operands are interpreted and cannot be used in Type 1 statements, which are completely compiled. Type 2 operators/operands can be used in Type 2 statements, which are only partially compiled. Type 3 statements are not supported by the compiler. In most cases this is because the statement does not make sense in a compiled environment, or because the statement is outside the scope of the compiler design. A list showing the type of each statement, operator and operand is given in the Statement Lists section.

The following table shows the legal combinations between the statement types and the operator/operand types.

Statement Type	Operator/Operand Type
	1	2
1	Preferred	Illegal
2	Legal	Legal
3	—	—


Special Statements

Several statements do not strictly adhere to the statement type rules given above. The following paragraphs discuss these special statements.

The LET statement can include type 2 operators or operands. If it does, the LET statement is evaluated by the interpreter. If not, it is fully compiled.

The control expression in an IF, UNTIL, or WHILE statement may contain type 2 operands and operators. If it does, the expression is evaluated by the interpreter. If not, the statement is fully compiled.

In a CSUB, a PAUSE statement is not allowed. It is changed into a STOP statement and a warning message is generated. All PAUSE statements should be examined to insure that a STOP statement performs the intended action.


Use STORE for CSUBs

The SAVE statement produces an ASCII copy of your program. Since only the first line of a CSUB is in ASCII, the remainder, in machine code, should not be saved with the SAVE statement. To save a program that contains CSUBs, use the STORE or RE-STORE statements.


Event Checking

No event checking is done while a CSUB is running. This means the ON event statement cannot be used, and previous ON event statements will not be serviced while a CSUB is executing.

Since keyboard servicing is dependent upon events, the keyboard will not respond while a CSUB is executing. This does not include the Ctrl-Alt-Del key sequence, which causes the computer to re-boot. However, if a keyboard input statement is included in the CSUB, the keyboard will be serviced while the INPUT or ENTER KBD statement is active.

The RESET key is normally ignored while a SUB is executing unless the Produce End-Of-Line in the code compiler switch is used, as explained in the previous Compiler Switches section.


Calling Other SUBs

One CSUB may call another CSUB, but it may not call an interpreted SUB. If an attempt is made to do this, HTBasic gives Error 2012 at runtime. Use "XREF sub-name:SB" to list the SUBs called by the CSUB. Then make sure they are compiled and that no interpreted SUBs of the same names exist before the compiled SUBs in the program.

Some users report that it is possible to call an interpreted SUB by changing it into a user defined function (DEF FN) and then calling it with a statement such as:

Dummy = FNRoutine(Parameters)

However, calling interpreted SUBs from within compiled SUBs using any method is not officially supported. One known problem involves DELSUB. If an interpreted SUB has been called by a compiled SUB and DELSUB is used, the location of the CSUB code may move. When control returns to the CSUB, the computer will crash.


CSUB Library Routines

The compiler generates code that prevents the CSUB from calling a runtime library routine that is not present in the release of HTBasic that is running the CSUB. If the CSUB attempts to use a runtime library routine that is not in the release of HTBasic running the CSUB, "Error 2009, Wrong Revision" is given. To correct this problem, use a release of HTBasic that matches or exceeds the release number of the numeric compiler.

CSUBs compiled with revision 9.0 or later of the numeric compiler require HTBasic revision 9.0 or later to execute.


Code Size

One of the strongest advantages of an interpreter is that the interpreted code is usually smaller than the corresponding compiled code. So, where size is an issue, use interpreted subprograms. Where speed is an issue, use compiled subprograms. Remember that compiled and interpreted subprograms can exist in the same PROG file.

No provision exists to produce smaller code size in a CSUB. When a trade-off exists between faster or smaller code size, the compiler generates faster code. When a subprogram is compiled, its size will change. Usually, the size of a compiled subprogram is bigger than the corresponding HTBasic subprogram, although this is not always the case. Consider the HTBasic program lines:

10  X=Y+Z

20  PRINT X

Line 10 occupies 18 bytes in interpreted HTBasic, but only 8 bytes in compiled HTBasic. Line 20, takes 12 bytes interpreted, but expands to 49 bytes when compiled. Type 2 statements always expand when compiled.


Precedence Rules

When possible, operations are made on constants at compile-time rather than at run-time. However, for compatibility with the interpreter, optimizations that would change the order of evaluation of operators are not made. For example, "X+5-2" will not be optimized since "+" and "-" evaluate left to right and are of equal precedence. Parentheses can be added to allow for optimization at compile-time. For example, "X+(5-2)" is optimized to "X+3."


Register Usage

Statements that require storage more intermediate than the CPU registers hold cause errors, allowing you to divide up the statement in whatever fashion makes the most sense in the context of your program.

It is not always obvious or intuitive what kind of statements will cause the registers to fill up. Consider this SUB:

30	 SUB R(INTEGER L,N(*),W,In(*))

40	INTEGER I,K,Wi,Wp,Nm0,Nmp,Nim,Ni,Nip

50	In(L,K)=N(L,I-1,K)*Wi*Wp/Nm0/Nmp+W-Nim/Ni-

     Nip*Wp*N(L,I,K)/(-Nm0)+Wi*N(L,I+1,K)/Nmp

90	In(L,K)=N(K,I-1,L)*(N(L,I,K)-N(L,I-1,K))

100	  	RETURN

110	SUBEND

Of lines 50 and 90, which would you guess is the line that causes a "Registers Full" error? Surprisingly, Line 50 is fine, but line 90 causes an error. Rather than trying to guess which lines in a SUB may be too complex, it is best to compile the program and let the compiler tell you. Then divide up those lines. For example, line 90 can be replaced with

60	INTEGER Temp

70	Temp=N(L,I,K)-N(L,I-1,K)

80	In(L,K)=N(K,I-1,L)*Temp

In general, avoid expressions that generate temporary results when evaluated from left to right. Keep references to COM variables and parameters to a minimum, especially array variables.


Precision

In some cases, the results of a math operation executed by the compiler differ from those produced by the interpreter. For example, SIN(.2) in DEG mode gives a slightly different result when executed by compiled code than when executed by the interpreter. Both the interpreter and the compiler truncate the 80-bit results produced by the math processor to the 64-bit REAL format used by HTBasic. However, optimizations used by the compiler may keep intermediate values in the math processor registers longer than the interpreter can. As a result, when the values differ, the value produced by the compiler is usually more accurate.


Errors

When an error occurs while executing a CSUB, the line reported is the line number of the CSUB.

Many error conditions are ignored if checking for the condition would slow down run-time execution speed. By knowing what errors are ignored, tests for the error conditions can be limited to instances in the program that require it. If returning an error number which matches the number produced by the interpreter would slow down non-error execution of a statement, the compiler may opt to return a more generic error number with code that executes faster.

If the bit number in a BIT statement or the shift value in a SHIFT or ROTATE statement is too large or too small, no error is detected unless the value is specified as a constant. If the value is not a constant, then the shift value is treated as (value MOD 16) by the hardware. Array bound checks are not made unless the subscript is a constant, the array is a local array, and the Disallow REDIM and produce faster array code compiler switch is used, as explained in the previous Compiler Switches section.

Variables are not checked for "Reference to missing OPTIONAL Parameter" or "Variable not Allocated" errors. If a missing parameter or un-ALLOCATEd variable is used, it can cause HTBasic to crash, or cause loss of data. Don't use OPTIONAL parameters without checking NPAR first, and don't use ALLOCATEd variables before they are ALLOCATEd or after they are DEALLOCATEd.

Integer overflow of the FOR loop control-variable is ignored. As a result, a FOR loop which required an ON ERROR statement to terminate in the interpreter will run forever after being compiled. An example of a FOR loop with this problem is:

10	INTEGER I

20	ON ERROR GOTO 60

30	FOR I=0 TO 32767 STEP 10

40	     PRINT I

50	NEXT I

60	OFF ERROR


SIN and COS

Arguments to SIN and COS must be less than 2^63 radians in magnitude. If greater, the argument is returned unchanged.


Hidden Program Errors

The compiler will sometimes uncover hidden errors in your program that the interpreter fails to discover.


RESTORE

The compiler requires each RESTORE statement referencing a program line to reference a DATA statement. This rule is more strict than the rule imposed by the interpreter, which allows the RESTORE statement to reference any line in the subprogram. Rather than check your SUB to see if this is the case, try compiling it. If any problems exist, the compiler will generate errors.

To correct a problem RESTORE statement, look in your program at the RESTORE statement to see which line is specified. Go to that line and look forward through the program until a DATA statement is found. Use the line number of that DATA statement in the RESTORE statement, or add a line label to the DATA statement and use the label in the RESTORE statement.


Release Specific Limitations

Release 9.0 or higher of the Numeric Compiler is required to compile PROG files produced with release 9.0 or higher of HTBasic.


Producing Optimal CSUBs

This chapter presents several hints that can help produce better CSUBs.


Variables and Expressions

Local variables can be accessed faster than other variables; COM variables are the slowest and should be avoided whenever possible. Turning the Disallow REDIM and produce faster array code compiler switch on and using local arrays is faster and produces less code than other array types.

Sometimes, as mentioned earlier, adding parentheses can allow greater optimization by the compiler. For example, X*180/PI can be entered as X*(180/PI) for a speed increase. Using radians is faster than degrees.


Use INTEGERs

INTEGER operations are much faster than REAL operations, especially in FOR loops and array subscripts. For example, adding line 30 to the following subprogram makes the program run much faster.

20	 SUB Sum(A(*),S)

40	FOR I=1 TO 100

50	  S=S+A(I)

60	NEXT I

70	 SUBEND

Line 30 declares I as INTEGER:

30	INTEGER I


Loop Constructs

Depending on the loop conditions, a REPEAT/UNTIL loop generally executes faster than a WHILE loop. A FOR loop is faster if the control variable is an INTEGER rather than a REAL.

A FOR loop executes faster and produces less code if the STEP size is a constant. A STEP size is a constant if it does not depend on the value of a variable. For example:

FOR I=First TO Last STEP 2	! constant

FOR I=First TO Last	 ! constant (STEP 1)

FOR I=First TO Last STEP X	! variable

FOR I=First TO Last STEP 2*4 ! constant

FOR I=First TO Last STEP 2*X ! variable


Size of CSUB

The size of an HTBasic subprogram sometimes can be made a little smaller if unused control information is eliminated from the subprogram before compiling. To do this, SAVE the program in ASCII to a temporary file and then GET the program from that file. This pair of statements discards any unused control information. Finally, prerun and RE-STORE the program. If this is done before compiling, the compiler can avoid carrying unnecessary control information into the compiled subprogram.


Use Type 1 Statements

The compiler is at its best when compiling numerically intensive code. It is suggested that you partition numerically intensive code into subprograms separate from code that does I/O and graphics. Then compile just the numeric subprograms.

Type 1 statements are completely compiled and should be used whenever possible. Type 1 statements enjoy the greatest speed increase from compilation. A list of type 1 statements is given in the Statement Lists section. Generally speaking, type 1 statements are flow control statements and assignment statements.

As an example, LET is a type 1 statement but DRAW is not. The following two subprograms produce equivalent results, but the second will run faster because the calculations have been moved into a type 1 statement.

40	SUB Graph

50	WINDOW 0,100,-100,100

60	AXES

70	FOR X=0 TO 100

80	DRAW X,(X-70)*(X-30)*(X-10)/500

90	NEXT X

100	SUBEND

40	 SUB Graph

50	WINDOW 0,100,-100,100

60	AXES

70	FOR X=0 TO 100

80	Y=(X-70)*(X-30)*(X-10)/500

81	DRAW X,Y

90	NEXT X

100	SUBEND

Some operators and operands are interpreted and cannot be used with type 1 statements. These are called type 2 operators/operands and are listed in the Statement Lists section. Generally speaking, a string, complex number, I/O path, or whole array is a type 2 operand and most operators that require one of these operands are type 2 operators.


Using Type 2 Operators & Operands

Avoid using type 2 operators/operands whenever possible, since the compiler is not designed to handle them. However, at times it becomes necessary to use a type 2 operator/operand. If you attempt to use a type 2 operator/operand in a type 1 statement (except IF, UNTIL, or WHILE), you will get the error, "must be moved out of Type 1 statement."

An assignment statement, with or without a LET, is used to correct this error. An assignment statement is a switch hitter – it can be either a type 1 statement or a type 2 statement. This provides a method of resolving conflicts between type 1 statements and type 2 operators/operands. An example will help illustrate this. Suppose you have the following subprogram:

10  SUB Frequency(A(*))

20	SELECT SUM (A(*))

30  	      CASE >100.0

 .

90	 END SELECT

 .

110	END IF

120 SUBEND

Unchanged, this subprogram will give a compile error in line 20. The SELECT statement is a type 1 statement and SUM is a type 2 operator. Since an assignment statement can accept a type 2 operand, the expression in line 20 should be moved to an assignment statement. This has been done in line 20 in the listing below.

10  SUB Frequency

11	 INTEGER Sum

  .

20	Sum=SUM(A(*))

30	SELECT Sum

40  	     CASE >100.0

 .

90	 END SELECT

 .

110	END IF

120 SUBEND

Assignment statements execute more slowly when type 2 operators/operands are included, so keep the use of type 2 operators to a minimum. Type 1 statements and type 2 operators/operands are listed in the Statement Lists section.

Consider another example. In the following listing, note that lines 100 and 110 both can be used at the beginning of a SUB to set Color to 1 if color capabilities are present. However, while line 100 will give a compiler error, line 110 does not.

100	IF POS(SYSTEM$("CRT ID"),"C")=7 THEN Color=1

110	Color=POS(SYSTEM$("CRT ID"),"C")=7


Errors

This appendix lists the compiler warning and error messages, as well as the HTBasic error numbers that can be generated by the compiler, and some of the more common runtime error messages.


Compiler Warning Messages

The following compiler warning messages, with error (warning) numbers between 1 and 99, are compile time warnings. All warning messages, except 16, are suppressed unless the Print Warning Messages compiler switch is specified. Warning message number 16 is never suppressed.


Error 3

A compiler switch was ignored because it must be specified before any statements that produce executable code. Move the switch so it immediately follows the SUB line.


Error 4

The use of a REAL expression is slower than an INTEGER expression. If possible, use INTEGER rather than REAL variables and operators.


Error 10

The subprogram was not compiled for the reason given in the error message.


Error 13

CONFIGCHECK requires one register to execute. In this particular instance CONFIGCHECK was turned OFF because no register was available. It was then turned back on. If this instance really needs to have CONFIGCHECK ON, divide the statement into two in order to free up a register for the check.


Error 14

REDIM of local arrays is only safe if the Disallow REDIM and produce faster array code compiler switch is off. REDIM of COM variables, parameters and ALLOCATEd arrays is fine regardless of the state of the Disallow REDIM and produce faster array code compiler switch.


Error 15

Usually, a subprogram is copied in its interpreted state to the CSUB output file if it cannot be compiled. In this instance, some problem prevented the subprogram from being copied. It will not appear in the output file, in HTBasic or CSUB form. You can, however, LOAD the output file into HTBasic, append the subprogram using LOADSUB, then RE-STORE the output file.


Error 16

Compiled subprograms cannot be paused. Therefore, all PAUSE statements are converted into STOP statements. Examine the program and see what action should be taken in place of the PAUSE statement.


Error 36

One of the compiler files has been corrupted. Install the compiler again.


Compiler Error Messages

The following compiler error messages, with error numbers between 100 and 999, are compile time errors. These messages are always displayed. If any of these errors occur at compile, it will be necessary to fix the problem and re-compile.


Error 101

This subprogram was not compiled because it has not been prerun. To prerun all the subprograms in a file:

• run HTBasic,

• LOAD the file,

• if the file has no END statement, add one as the first line in the file,

• press the STEP key once,

• then RE-STORE the file.


Error 203

When the compiler tried to open the file, the error number printed in the error message was generated. Also, the Windows error message should be displayed in a dialog box.  If you are in doubt about the meaning of the error, consult your Windows manual.


Error 204

When the compiler tried to read from the file, the error number printed in the error message was generated. Also, the Windows error message should be displayed in a dialog box.  If you are in doubt about the meaning of the error, consult your Windows manual.


Error 205

The input file is not a PROG file or the PROG file has the wrong binary revision. The HTBasic CAT command will show the file types for each file in a directory and is a good way of checking to see if the file is a PROG file. Remember to use STORE or RE-STORE to create PROG files (and not SAVE/RE-SAVE, which create ASCII files). If the PROG file has the wrong binary revision, check the Release number of HTBasic used to create the PROG file. Then compare it to the Release number requirements listed earlier in this manual.


Error 206

When the compiler tried to write to a file, the error number printed in the error message was generated. Also, the Windows error message should be displayed in a dialog box.  If you are in doubt about the meaning of the error, consult your Windows manual.  Check to make sure there is enough room on the disk. Make sure floppy disks are not write protected. If on a network, make sure your computer has write permission in the directory containing the file.


Error 207

Either not enough memory was available or a particular subprogram was larger than the available memory. In the former case, try eliminating TSR programs or changing your CONFIG.SYS and AUTOEXEC.BAT files to increase the amount of memory available. If a particular subprogram is too large, divide it into multiple subprograms.


Error 208

An unexpected condition occurred. Please contact TransEra Technical Support. Be prepared to supply a copy of the program you were compiling, as well as information about your computer system.


Error 209

The statement is too complex. Divide the statement into two statements.


Error 210

A type 2 operator, operand, variable type or feature that is not supported in type 1 statements was used. The operator or variable type can still be used, but must be moved to an assignment statement. Refer to the sections "Use Type 1 Statements" and "Using Type 2 Operators/Operands."


Error 211

The subprogram is too complex. Divide the subprogram into two subprograms.


Error 212

This statement cannot be included in a compiled subprogram. If you wish to compile this subprogram, you must change the subprogram so that this statement is not included.


Error 213

The compiler requires that the RESTORE statement specifies a line with a DATA statement. Look in your program at the RESTORE statement to see which line is specified. Go to that line and look forward through the program until a DATA statement is found. Use the line number of the DATA statement in the RESTORE statement, or add a line label to the DATA statement and use the label in the RESTORE statement.


Error 214

The action clause of a single line IF statement must be a type 1 statement. It must also meet the normal rules for IF statements imposed by the interpreter. In practice, it must be either a line number, line label, or an assignment statement.


Error 215

The SUB named for compilation does not exist in the source file. While HTBasic is running, type

CAT "filename"

to see a list of the subprograms in the source file. Make sure you spell the name correctly. Or use the Select button in the HTBasic Numeric Compiler window to select the SUB name.


Error 216

The default number of temporary data space, eight, was not enough. Use the Allocate data space for temporary results compiler switch to specify a larger value.


HTBasic Error Numbers

Error numbers greater than 1000 are HTBasic error numbers with 1000 added. Refer to the HTBasic Reference Manual for a list of HTBasic errors. Errors that occur at run-time are standard HTBasic errors and are listed in the back of the HTBasic Reference Manual.  The following are some of the more common run-time error messages.


Error 1003

The specified program line could not be found in this context. A program line number referenced in a GOTO, GOSUB, or other statement references a line number that is not defined within the subprogram. Examine the program and correct the statement.


Error 1017

An array subscript value is outside the specified dimension bounds. Examine the program and correct the subscript value.


Error 1020

The value calculated exceeds the range that an INTEGER can hold: -32768 through +32767.


Error 1022

The value calculated is too big to be represented by the REAL data type See MINREAL and MAXREAL in the HTBasic Reference Manual.


Error 1027

An attempt was made to raise a negative number to a non-integer power. Examine the program and correct the statement.


Error 1031

The divisor specified was zero, or an operation was attempted that resulted in a division by zero.


Error 1620

A COMPLEX value was encountered and is not supported in this statement.


Error 2009

The CSUB you attempted to execute was created by another release of the numeric compiler and is not compatible with the version of HTBasic that is running.


Error 2012

The CSUB attempted to CALL an interpreted SUB, which is not supported. Use "XREF sub-name : SB" to list the SUBs called by sub-name. Then make sure they are compiled, or that no interpreted SUBs of the same name exist before the compiled SUBs.


Definitions

In addition to the definitions given here, the HTBasic Reference Manual contains a section of definitions, which you may find helpful. They can be found Chapter 2 of the HTBasic Reference Manual.


Compile-time

An action that occurs at compile-time occurs while the compiler is running. An action that occurs at run-time occurs when the compiled subprogram is running.


Compiler

A program that reads HTBasic programs and produces equivalent machine code programs.


CSUB

A subprogram that contains machine code rather than HTBasic code. When viewed within HTBasic, it consists of a CSUB statement and sometimes several additional line numbers, each reserved with an asterisk. CSUBs are produced with the HTBasic for Windows 9.3 Numeric Compiler or the CSUB Toolkit. The compiler produces CSUBs from HTBasic subprograms while the CSUB toolkit produces CSUBs from C or Pentium assembly language subroutines.


DEF FN

See "User defined function."


Environment Manager

The necessary code to support the HTBasic runtime environment. The HTBasic environment includes support for the softkeys, the extended output area, the display and keyboard lines, event handling, and live-keyboard execution. Other languages typically lack these environmental features.


In-line

The function does not require a library call for evaluation. Whatever machine codes are required to execute the instruction are placed in the program at the point where the function is specified in HTBasic.


Interpreter

A program that runs programs written in ASCII or tokenized form. Tokenized code typically represents operations more complex than the operations supported by machine code.  Thus tokenized programs are typically smaller than equivalent machine code programs. Interpreters are thus used quite often, if only internally, for parts of popular computer applications such as Microsoft Excel and Microsoft Word.


Machine Code

The values which a computer processor reads as instructions. Machine code instructions are not very powerful and several instructions may be needed to execute even the simplest HTBasic statement. Machine code is specific to a processor or family of processors. Additional instructions are usually added to newer members of a processor family.


Main Program

The first part of the HTBasic program, not including any SUB or DEF FN programs. The main program contains HTBasic statements. It begins with the first line in the program and ends with the program line containing the END statement. The Main program begins running when the RUN statement is entered or the RUN key is pressed.

If the PROG file has no Main program, you must add one before the file can be prerun. In many cases, inserting an END statement before the first SUB or DEF statement will suffice. However, if any of the subprograms contain COM statements without array subscript bounds or string lengths, then COM statements that appropriately declare them must be added to the Main program.


Prerun

This is an advanced feature of the HTBasic interpreter that most language vendors reserve for compiler products. TransEra placed the prerun code in the interpreter so that both interpreter and compiler users could benefit from it. When code is prerun, the interpreter syntax checks multi-line structures. The consistency of variable declarations is verified. Unless CONFIGURE DIM has been turned OFF, any required dimensioning for implicit variables and strings is done. Memory allocation for variables is calculated. A subprogram may be STOREd to a file either before or after it has been prerun. Making changes to a subprogram invalidates any previous prerun. Running a program automatically causes the prerun to occur. Pressing the STEP key once while the program is STOPped is a handy way to force a prerun to occur while not actually executing any program lines.


PROG file

The file type used to hold binary program images. PROG files are the most efficient file type for storing HTBasic programs. Use STORE to create a PROG file containing the program currently in memory.  SAVE creates an ASCII file, not a PROG file. A PROG file can contain CSUBs, while an ASCII file cannot.


Program Context

A program unit with its own environment, including local variables, which can be called recursively by other program contexts and can pass arguments, either by reference or by value. There are four types of program contexts: 1) the main program, 2) an HTBasic subprogram (SUB), 3) a user defined function (DEF FN) and 4) a compiled subprogram (CSUB).


Run-time

An action that occurs at compile-time occurs while the compiler is running. An action that occurs at run-time occurs when the compiled subprogram is running.


SUB

See Subprogram.


Subprogram

A subroutine that contains HTBasic statements or compiled machine code. It begins with a SUB or CSUB statement. In the case of a SUB, it ends with a SUBEND statement. It is called with a CALL statement. Arguments can be passed to a subprogram. The term subprogram is used instead of subroutine in order to differentiate subroutines that have their own program contexts (called with the CALL statement) from subroutines within the main program context (called with the GOSUB statement).


Type 1 Statement

A statement that is completely compiled by the compiler. Type 1 statements are generally flow control or numerically intensive statements. Type 1 statements are listed in the Statement Lists section.


Type 2 Operator/Operand

An operator or operand that is completely interpreted and hence cannot occur in a type 1 statement. Type 2 operators/operands are listed in the Statement Lists section. Generally speaking, a string, complex number, I/O path, or whole array is a type 2 operand, and most operators that require one of these operands are a type 2 operator. Technically speaking, any operator or operand that uses an internal or external data structure larger than eight bytes is a type 2 operator/operand.


User Defined Function

A user-defined function contains HTBasic statements. It begins with a DEF statement and ends with an FNEND statement. It is called from within a numeric or string expression by referencing its name. It terminates and returns a value with a RETURN statement. The expression then continues to evaluate, using the value returned in place of the function reference. Arguments can be passed to a function.


Statement Lists

This section lists the supported and unsupported statements, operators and operands.


Supported Statements

The following tables list the supported type 1 (compiled) and type 2 (interpreted) statements. Note that the LET statement can handle both type 1 and type 2 operators and operands.


Type 1 Statements

The type 1 statements are completely compiled by the compiler. They are generally flow control or numerically intensive statements. They cannot contain a type 2 operator or operand.

CASE	CAUSE ERROR	COM	DIM
ELSE	END IF	END LOOP	END SELECT
END WHILE	END	EXIT IF	FOR
GOSUB	GOTO	IF (block)	IF
INTEGER	LET	(implied LET)	LOOP
NEXT	ON index	OPTION BASE	REAL
REM	REPEAT	RETURN	SELECT
SUB	SUBEND	SUBEXIT	UNTIL
WHILE


Type 2 Statements

A type 2 statement cannot be compiled by the compiler, so it is interpreted. A type 1 statement that contains a type 2 operator or operand is a type 2 statement. Note that the LET statement can handle type 2 operators and operands.

ABORT	ALLOCATE	ALPHA	AREA	ASSIGN
AXES	BEEP	BREAK	CALL	(Implied CALL)
CAT	CHANGE	CHECKREAD	CHGRP	CHOWN
CLEAR	CLIP	COMPLEX	CONFIGURE	CONT
CONTROL	COPY	COPYLINES	CREATE	CSIZE
DATA	DEALLOCATE	DEG	DEL	DIGITIZE
DISABLE	DISP	DISPLAY	DRAW	DUMP
EDIT	ENABLE	ENTER	EXECUTE	FIND
FNEND	FRAME	GCLEAR	GESCAPE	GINIT
GLOAD	GRAPHICS	GRID	GSEND	GSTORE
HELP	IDRAW	IMAGE	IMOVE	INDENT
INPUT	IPLOT	KBD	KEY LABELS	LDIR
LEXICAL ORDER IS	LINE	LINK	LINPUT	LIST
LOADSUB	LOCAL	LOCK	LORG	MASS
MAT	MERGE ALPHA WITH GRAPHICS	MOVE	MOVELINES	MASS STORAGE IS
OUT	OUTPUT	OUTW	PASS CONTROL	PDIR
PEN	PENUP	PERMIT	PIVOT	PLOT
PLOTTER IS	POLYGON	POLYLINE	PPOLL	PRINT
PRINTALL IS	PRINTER IS	PROTECT	PURGE	QUIT
RAD	RANDOMIZE	RE-STORE	READ	RECTANGLE
REDIM	REMOTE	REN	RENAME	REQUEST
RESET	RESTORE	RESUME INTERACTIVE	RPLOT	RUN
RUNLIGHT	SCRATCH	SECURE	SEND	SEPARATE ALPHA FROM GRAPHICS
SET	SHOW	SIGNAL	STATUS	STOP
STORE	SUSPEND INTERACTIVE	SYMBOL	SYSTEM	TRACE
TRACK	TRIGGER	UNLOCK	USER KEYS	VIEWPORT
WAIT	WHERE	WILDCARDS	WINDOW	WRITEIO
XREF


Non-supported Statements (Type 3)

The following table lists the non-supported or type 3 statements. The PAUSE statement is changed into a STOP statement.

DEF FN	DELSUB	ERROR	FN
GET	LOAD	ON/OFF event	PAUSE
RE-SAVE	SAVE	TRACE


Operators and Operands

Type 1 operators are completely compiled, whereas, type 2 operators are interpreted. Type 2 operands are strings, complex numbers, I/O paths, or whole arrays. The following tables list the type 1 and type 2 operators and operands.


Type 1 Operators

The type 1 operators are completely compiled by the compiler and can appear in a type 1 statement.

Monadic +	Monadic -	+	-	*	/
^	= (assignment)	= (logical)	<>	<	<=
>	>=	() parentheses	ABS	ACS	ALLOCATEd Variables
AND	ASN	ATN	ATN2	Array subscripts	BINAND
BINCMP	BINEOR	BINEQV	BINIMP	BINIOR	BIT
CHRX/CHRY	CINT	COM Variables	COS	CRT	DIV
EXOR	EXP	FIX	FRACT	FRE	Hex Constants
INP/INPW	INT	Integer Constants	Integer Variables	KBD	LGT
LOG	Local Variables	MAXREAL	MINREAL	MOD	MODULO
NOT	NPAR	Octal Constants	OR	PI	PRT
Parameter Variables	RATIO	REAL	Real Constants	Real Variables	RND
ROTATE	SGN	SHIFT	SIN	SQR	STATUS()
SUM	TAN	TIMEDATE


Type 2 Operators and Operands

The type 2 operators and operands are interpreted and, therefore, cannot occur in a type 1 statement. Generally speaking, a string, complex number, I/O path, or whole array is a type 2 operand and most operators that require one of these operands are type 2 operators.

& (String concatenation)	ACSH	ARG	ASNH	ATNH
BASE	CHR$	CMPLX	COMMAND$	CONJG
COSH	Complex Literals	Complex Variables	DATE/DATE$	DET/DET()
DOT	DROUND	DVAL/DVAL$	ENFIRON$	ERRL/ERRLN/ERRN
ERRM$	IMAG	INMEM	IVAL/IVAL$	KBD$
KNOBX/KNOBY	LEN	LWC$	MAX	MAXLEN
MIN	NUM	POS	PPOLL	PROUND
RANK	READIO	RES	REV$	RPT$
SC	SINH	SIZE	SPOLL	SYSTEM$
String Literals	String Variables	Sub-strings [ ]	TANH	TIME/TIME$
TRIM$	UPC$	VAL/VAL$